<?php
class system_db_adapter_pdo_mysql extends system_db_adapter_pdo_abstract {
	protected $_pdoType = 'mysql';
	
	protected $_numericDataTypes = array(system_db::INT_TYPE => system_db::INT_TYPE, system_db::BIGINT_TYPE => system_db::BIGINT_TYPE, system_db::FLOAT_TYPE => system_db::FLOAT_TYPE, 'INT' => system_db::INT_TYPE, 'INTEGER' => system_db::INT_TYPE, 'MEDIUMINT' => system_db::INT_TYPE, 'SMALLINT' => system_db::INT_TYPE, 'TINYINT' => system_db::INT_TYPE, 'BIGINT' => system_db::BIGINT_TYPE, 'SERIAL' => system_db::BIGINT_TYPE, 'DEC' => system_db::FLOAT_TYPE, 'DECIMAL' => system_db::FLOAT_TYPE, 'DOUBLE' => system_db::FLOAT_TYPE, 'DOUBLE PRECISION' => system_db::FLOAT_TYPE, 'FIXED' => system_db::FLOAT_TYPE, 'FLOAT' => system_db::FLOAT_TYPE);
	protected function _connect() {
		if($this->_connection) {
			return;
		}
		
		if(!empty($this->_config['charset'])) {
			$initCommand = "SET NAMES '".$this->_config['charset']."'";
			$this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND
		}
		
		parent::_connect();
	}
	
	public function getQuoteIdentifierSymbol() {
		return "`";
	}
	
	public function listTables() {
		return $this->fetchCol('SHOW TABLES');
	}
	
	public function describeTable($tableName, $schemaName = null) {
		if($schemaName) {
			$sql = 'DESCRIBE '.$this->quoteIdentifier("$schemaName.$tableName", true);
		} else {
			$sql = 'DESCRIBE '.$this->quoteIdentifier($tableName, true);
		}
		$stmt = $this->query($sql);
		
		// Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection
		$result = $stmt->fetchAll(system_db::FETCH_NUM);
		
		$field = 0;
		$type = 1;
		$null = 2;
		$key = 3;
		$default = 4;
		$extra = 5;
		
		$desc = array();
		$i = 1;
		$p = 1;
		foreach($result as $row) {
			list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity) = array(null, null, null, null, false, null, false);
			if(preg_match('/unsigned/', $row[$type])) {
				$unsigned = true;
			}
			if(preg_match('/^((?:var)?char)\((\d+)\)/', $row[$type], $matches)) {
				$row[$type] = $matches[1];
				$length = $matches[2];
			} else 
				if(preg_match('/^decimal\((\d+),(\d+)\)/', $row[$type], $matches)) {
					$row[$type] = 'decimal';
					$precision = $matches[1];
					$scale = $matches[2];
				} else 
					if(preg_match('/^float\((\d+),(\d+)\)/', $row[$type], $matches)) {
						$row[$type] = 'float';
						$precision = $matches[1];
						$scale = $matches[2];
					} else 
						if(preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row[$type], $matches)) {
							$row[$type] = $matches[1];
						
		// The optional argument of a MySQL int type is not precision
						// or length; it is only a hint for display width.
						}
			if(strtoupper($row[$key])=='PRI') {
				$primary = true;
				$primaryPosition = $p;
				if($row[$extra]=='auto_increment') {
					$identity = true;
				} else {
					$identity = false;
				}
				++$p;
			}
			$desc[$this->foldCase($row[$field])] = array(
				'SCHEMA_NAME' => null,
				'TABLE_NAME' => $this->foldCase($tableName), 
				'COLUMN_NAME' => $this->foldCase($row[$field]), 
				'COLUMN_POSITION' => $i, 
				'DATA_TYPE' => $row[$type], 
				'DEFAULT' => $row[$default], 
				'NULLABLE' => (bool) ($row[$null]=='YES'), 
				'LENGTH' => $length, 
				'SCALE' => $scale, 
				'PRECISION' => $precision, 
				'UNSIGNED' => $unsigned, 
				'PRIMARY' => $primary, 
				'PRIMARY_POSITION' => $primaryPosition, 
				'IDENTITY' => $identity
			);
			++$i;
		}
		return $desc;
	}
	
	public function limit($sql, $count, $offset = 0) {
		$count = intval($count);
		if($count<=0) {
			throw new system_db_adapter_exception("LIMIT argument count=$count is not valid");
		}
		
		$offset = intval($offset);
		if($offset<0) {
			throw new system_db_adapter_exception("LIMIT argument offset=$offset is not valid");
		}
		
		$sql .= " LIMIT $count";
		if($offset>0) {
			$sql .= " OFFSET $offset";
		}
		
		return $sql;
	}

}